package cn.ronghuanet.user.service.impl;

import cn.ronghuanet.auth.service.ILoginService;
import cn.ronghuanet.base.constants.BaseConstants;
import cn.ronghuanet.base.constants.WxConstants;
import cn.ronghuanet.base.exception.ResponseCode;
import cn.ronghuanet.base.exception.RonghuaAssert;
import cn.ronghuanet.base.util.HttpUtil;
import cn.ronghuanet.user.domain.Wxuser;
import cn.ronghuanet.user.dto.WechatBindDTO;
import cn.ronghuanet.user.mapper.WxuserMapper;
import cn.ronghuanet.user.rabbitmq.config.RegisterNoticeRabbitmqConfig;
import cn.ronghuanet.base.util.MD5Utils;
import cn.ronghuanet.user.domain.Logininfo;
import cn.ronghuanet.user.domain.User;
import cn.ronghuanet.user.dto.SendEmailDTO;
import cn.ronghuanet.user.dto.SendSmsDTO;
import cn.ronghuanet.user.dto.UserRegisterDTO;
import cn.ronghuanet.user.mapper.LogininfoMapper;
import cn.ronghuanet.user.mapper.UserMapper;
import cn.ronghuanet.user.service.IUserService;
import cn.ronghuanet.base.service.impl.IBaseServiceImpl;
import com.alibaba.fastjson.JSONObject;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import sun.rmi.runtime.Log;

import java.util.Date;
import java.util.Map;
import java.util.Objects;
import java.util.UUID;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author lijie
 * @since 2023-08-25
 */
@Service
public class UserServiceImpl extends IBaseServiceImpl<User> implements IUserService {

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private LogininfoMapper logininfoMapper;

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Autowired
    private WxuserMapper wxuserMapper;

    @Autowired
    private ILoginService loginService;

    @Transactional
    @Override
    public void register(UserRegisterDTO dto) {
        // 1 参数校验
        // 1.1 校验手机验证码是否正确
        // 1.1.1 获取该手机号的验证码
        String smsCodeByRedis = (String)redisTemplate.opsForValue().get(BaseConstants.REGISTER_SMS_VERIFY_CODE_KEY + dto.getPhone());
        // 1.1.2 如果验证码为空,说明已过期,要提示错误信息
        RonghuaAssert.isNotBlank(smsCodeByRedis, ResponseCode.RESPONSE_CODE_40020);
        // 1.1.3 不为空就要和前端输入的验证码做比较
        String smsCode = smsCodeByRedis.split(":")[0];
        RonghuaAssert.isEqIgnoreCase(smsCode,dto.getSmsCode(),ResponseCode.RESPONSE_CODE_40021);

        // 1.2 两次密码是否一致
        RonghuaAssert.isEq(dto.getConfirmPassword(),dto.getPassword(),ResponseCode.RESPONSE_CODE_40011);

        // 1.3 校验用户名或邮箱是否存在  用户名和邮箱只要有一个不为空,都要返回错误信息
        int count = userMapper.loadByUsernameOrEmail(dto.getUsername(),dto.getEmail());
        RonghuaAssert.isZero(count,ResponseCode.RESPONSE_CODE_40022);

        // 2 保存logininfo信息到数据库
        Logininfo logininfo = new Logininfo();
        logininfo.setUsername(dto.getUsername());
        logininfo.setPhone(dto.getPhone());
        logininfo.setEmail(dto.getEmail());
        // 密码要做加盐加密处理
        String salt = UUID.randomUUID().toString();
        String password = MD5Utils.encrypByMd5("ronghuanet"+salt+dto.getPassword()+"123456");
        logininfo.setSalt(salt);
        logininfo.setPassword(password);
        logininfo.setType(1);
        logininfo.setDisable(1);
        logininfoMapper.insert(logininfo);

        // 3 保存user信息到数据库
        User user = new User();
        BeanUtils.copyProperties(logininfo,user);
        user.setId(null);
        user.setState(1);
        user.setAge(dto.getAge());
        user.setLogininfoId(logininfo.getId());
        user.setCreatetime(new Date());
        userMapper.insert(user);

        // 4 发送注册成功通知:短信通知,邮件通知
        // 发送邮件需要哪些参数, 主题,收件人,内容
        // 发送短信: 收件人的电话,内容
        SendSmsDTO sendSmsDTO = new SendSmsDTO("恭喜你,成功注册蓉车宝!新人活动正在开发欢迎参加!",dto.getPhone());
        rabbitTemplate.convertAndSend(RegisterNoticeRabbitmqConfig.EXCHANGE_TOPICS_INFORM,"inform.sms",sendSmsDTO);

        SendEmailDTO sendEmailDTO = new SendEmailDTO("注册成功通知","恭喜你,成功注册蓉车宝!新人活动正在开发欢迎参加!",dto.getEmail());
        rabbitTemplate.convertAndSend(RegisterNoticeRabbitmqConfig.EXCHANGE_TOPICS_INFORM,"inform.email",sendEmailDTO);
    }

    @Transactional
    @Override
    public Map<String, Object> bindWechat(WechatBindDTO dto) {
        // 1 参数校验
        // 1.1 参数非空校验
        RonghuaAssert.isNotBlank(dto.getAccessToken(),ResponseCode.RESPONSE_CODE_500);
        RonghuaAssert.isNotBlank(dto.getOpenid(),ResponseCode.RESPONSE_CODE_500);

        // 1.2 手机验证码校验
        String smsCodeByRedis = (String)redisTemplate.opsForValue().get(BaseConstants.BIND_SMS_VERIFY_CODE_KEY + dto.getPhone());
        RonghuaAssert.isNotBlank(smsCodeByRedis,ResponseCode.RESPONSE_CODE_40020);

        String smsCode = smsCodeByRedis.split(":")[0];
        RonghuaAssert.isEq(smsCode,dto.getVerifyCode(),ResponseCode.RESPONSE_CODE_40021);

        // 2 根据accessToken和openid调用微信接口获取微信用户信息
        String getUserUrl = WxConstants.GET_USER_URL.replace("ACCESS_TOKEN", dto.getAccessToken())
                .replace("OPENID", dto.getOpenid());
        String wxUserStr = HttpUtil.httpGet(getUserUrl);
        Wxuser wxuserObj = wxUserStr2Obj(wxUserStr);

        // 3 根据手机号获取t_user用户信息
        User user = userMapper.loadByPhone(dto.getPhone());
        Logininfo logininfo = null;
        // 4 如果用户信息不为空
        if(Objects.nonNull(user)){
            // 4.1 判断当前用户是否绑定微信用户
            Wxuser wxuser = wxuserMapper.loadByUserId(user.getId());
            // 4.2 如果绑定过,返回错误信息
            RonghuaAssert.isNull(wxuser,ResponseCode.RESPONSE_CODE_40025);
            // 4.3 如果没有绑定过
            logininfo = logininfoMapper.loadByUserId(user.getId());
        }else{
            // 5 如果用户信息为空
            // 5.1 创建登录信息t_logininfo,用户信息t_user,微信用户信息t_wxuser,并做好绑定,做免密登录
            // 新增t_logininfo表信息
            logininfo = createLogininfoByPhone(dto.getPhone());
            logininfoMapper.insert(logininfo);
            // 新增t_user表信息
            user = logininfo2User(logininfo);
            userMapper.insert(user);
        }
        // 4.3.1 新增微信用户信息并和手机号用户做绑定
        wxuserObj.setUserId(user.getId());
        wxuserMapper.insert(wxuserObj);
        // 4.3.2 免密登录
        Map<String, Object> map = loginService.loginSuccess(logininfo);
        return map;
    }

    private User logininfo2User(Logininfo logininfo) {
        User user = new User();
        BeanUtils.copyProperties(logininfo,user);
        user.setId(null);
        user.setState(1);
        user.setCreatetime(new Date());
        user.setLogininfoId(logininfo.getId());
        return user;
    }

    private Logininfo createLogininfoByPhone(String phone) {
        Logininfo logininfo = new Logininfo();
        logininfo.setUsername("car_"+UUID.randomUUID().toString());
        logininfo.setPhone(phone);
        String salt = UUID.randomUUID().toString();
        // 项目中密码如果要默认设置的话,一般有手机号后六位,或者123456,如果是默认设置的密码,用户登录以后要让用户即使修改,
        // 一般来说设置完密码以后可以给用户发送短信告知一下
        String password = MD5Utils.encrypByMd5("ronghuanet"+salt+"123456"+"123456");;
        logininfo.setSalt(salt);
        logininfo.setPassword(password);
        logininfo.setType(1);
        logininfo.setDisable(1);
        return logininfo;
    }

    private Wxuser wxUserStr2Obj(String wxUserStr) {
        JSONObject jsonObject = JSONObject.parseObject(wxUserStr);
        Wxuser wxuser = new Wxuser();
        wxuser.setOpenid(jsonObject.getString("openid"));
        wxuser.setNickname(jsonObject.getString("nickname"));
        wxuser.setSex(jsonObject.getInteger("sex"));
        wxuser.setAddress(jsonObject.getString("country")+jsonObject.getString("province")+jsonObject.getString("city"));
        wxuser.setHeadimgurl(jsonObject.getString("headimgurl"));
        wxuser.setUnionid(jsonObject.getString("unionid"));
        return wxuser;
    }
}
